
<?php
class IPv6PrefixMatcher {
    /**
     * 检查IPv6是否匹配指定CIDR前缀
     * @param string $ip 待检查的IPv6地址（支持压缩格式）
     * @param string $cidr CIDR表示法（如2001:db8::/32）
     * @return bool
     * @throws InvalidArgumentException
     */
    public static function match(string $ip, string $cidr): bool {
        if (strpos($cidr, '/') === false) {
            throw new InvalidArgumentException("Invalid CIDR format");
        }

        list($network, $prefixLen) = explode('/', $cidr);
        $prefixLen = (int)$prefixLen;
        
        if ($prefixLen < 0 || $prefixLen > 128) {
            throw new InvalidArgumentException("Prefix length must be 0-128");
        }

        try {
            $ipBin = self::ipToBinary($ip);
            $netBin = self::ipToBinary($network);
        } catch (Exception $e) {
            error_log("IP转换失败: " . $e->getMessage());
            return false;
        }
        
        if ($prefixLen === 0) return true; // 匹配所有地址
        
        // 生成位掩码
        $mask = self::createMask($prefixLen);
        return ($ipBin & $mask) === ($netBin & $mask);
    }

    private static function ipToBinary(string $ip): string {
        $expanded = self::expandIPv6($ip);
        $binary = inet_pton($expanded);
        if ($binary === false) {
            throw new InvalidArgumentException("Invalid IPv6 address");
        }
        return $binary;
    }

    private static function createMask(int $prefixLen): string {
        $mask = str_repeat("\xff", $prefixLen >> 3);
        if ($remain = $prefixLen % 8) {
            $mask .= chr(0xff << (8 - $remain));
        }
        return str_pad($mask, 16, "\x00", STR_PAD_RIGHT);
    }

    private static function expandIPv6(string $ip): string {
        if (strpos($ip, '::') !== false) {
            $parts = explode('::', $ip);
            $left = empty($parts[0]) ? [] : explode(':', $parts[0]);
            $right = empty($parts[1]) ? [] : explode(':', $parts[1]);
            $fill = 8 - count($left) - count($right);
            $ip = implode(':', array_merge($left, array_fill(0, $fill, '0'), $right));
        }
        return $ip;
    }
}

// // 使用示例
// $result = IPv6PrefixMatcher::match(
//     '2001:db8:abcd:12::1', 
//     '2001:db8:abcd::/48'
// ); // 返回true

// var_dump($result);
?>
